package com.ryan.quartz.temp;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

/**
 * <? extends T>：是指 “ 上界通配符 （Upper Bounds Wildcards） ”
 * <p>
 * <? super T>：是指 “ 下界通配符 （Lower Bounds Wildcards） ”
 *
 * @author Rayn on 2017/10/30.
 * @email liuwei412552703@163.com.
 */
public class GenericsExample {

    static class Species {
    }

    static class Human extends Species {
    }

    static class Man extends Human {
    }

    static class Woman extends Human {
    }


    static class ParameterizedTypeReference<T> {
        protected final Type type;

        public ParameterizedTypeReference() {
            Type superClass = this.getClass().getGenericSuperclass();
            //if (superClass instanceof Class) {
            // throw new IllegalArgumentException(
//"Internal error: TypeReference constructed without actual type information");
            //  } else {
            this.type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
            //}
        }

        public Type getType() {
            return type;
        }
    }

    /**
     * 如果频繁支持读取数据，不要求写数据，使用<? extends T>。即生产者 使用 <? extends T>
     * 如果频繁支持写入数据，不特别要求读数据，使用<? super T>。即消费者 使用 <? super T>
     * 如果都需要支持，使用<T>。
     *
     * @param args
     */
    public static void main(String[] args) {
        List<Human> list = new ArrayList<Human>();
        list.add(new Man());
        list.add(new Woman());
        Man o11 = (Man) list.get(0); // 这不能保证转型成功，也不是泛型的初衷
        Human o12 = list.get(0);

        List<? extends Human> list2 = new ArrayList<Human>();
//        list2.add(new Object()); // 编译错误：这不能写入元素，类型校验失败
//        list2.add(new Species()); // 编译错误：这不能写入元素，类型校验失败
//        list2.add(new Human()); // 编译错误：这不能写入元素，类型校验失败
//        list2.add(new Man()); // 编译错误：这不能写入元素，类型校验失败
//        list2.add(new Woman()); // 编译错误：这不能写入元素，类型校验失败
        Man o21 = (Man) list2.get(0);// 这不能保证转型成功，也不是泛型的初衷
        Human o22 = list2.get(0);

        List<? super Human> list3 = new ArrayList<Human>();
//        list3.add(new Object()); // 编译错误：这不能写入元素，类型校验失败
//        list3.add(new Species()); // 编译错误：这不能写入元素，类型校验失败
        list3.add(new Human());
        list3.add(new Man());
        list3.add(new Woman());
        Man o31 = (Man) list3.get(0); // 这不能保证转型成功，也不是泛型的初衷
//        Human o32 = list3.get(0); // 编译错误：无法自动转型为 Number
        Object o33 = list3.get(0);


/***********************************************************************************************************/
        // System.out.println(new ParameterizedTypeReference<String>().getType());
        // java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
        // 此处会输出报错，因此ParameterizedTypeReference 应不能直接实例化，可以考虑加abstract

        System.out.println(new ParameterizedTypeReference<String>() {
        }.getType());
        // ParameterizedTypeReference 的匿名内部类，可以触发super()，
        //即 ParameterizedTypeReference()的构造器逻辑，正常运行
    }
}
